home *** CD-ROM | disk | FTP | other *** search
- /*
- * DLAYER
- * Hardware level routines, data link layer
- *
- ****************************************************************************
- * *
- * part of: *
- * TCP/IP kernel for NCSA Telnet *
- * by Tim Krauskopf *
- * *
- * National Center for Supercomputing Applications *
- * 152 Computing Applications Building *
- * 605 E. Springfield Ave. *
- * Champaign, IL 61820 *
- * *
- * Copyright (c) 1987, Board of Trustees of the University of Illinois *
- * *
- ****************************************************************************
- */
- #include <stdio.h>
- #include <String.h>
- #include <Events.h>
- #include <AppleTalk.h>
-
- #include "protocol.h"
- #include "data.h"
- #include "mactools.h"
- #include "tools.h"
- #include "croft.h"
-
- extern int EtherNet; /* BYU 2.4.12 */
-
- /************************************************************************/
- /*
- * Address Resolution Protocol handling. This can be looked at as
- * Ethernet-dependent, but the data structure can handle any ARP
- * hardware, with minor changes here.
- *
- */
- replyarp(thardware,tipnum)
- uint8 *thardware,*tipnum;
- {
- uint8 *pc;
-
- movebytes(&arp.tha,thardware,DADDLEN); /* who this goes to */
-
- movebytes(&arp.tpa,tipnum,4); /* requester's IP address */
- arp.op = intswap(ARPREP); /* byte swapped reply opcode */
-
- movebytes(arp.d.dest,thardware,DADDLEN); /* hardware place to send to */
-
- dlayersend(&arp,sizeof(arp),0); /* BYU 2.4.15 */
-
- /*
- * check for conflicting IP number with your own
- */
- if (comparen(tipnum,nnipnum,4)) { /* we are in trouble */
- pc = neterrstring(-1);
- sprintf(pc,"Conflict with Ethernet hardware address: %2x:%2x:%2x:%2x:%2x:%2x",
- thardware[0],thardware[1],thardware[2],thardware[3],thardware[4],thardware[5]);
- netposterr(-1);
- netposterr(102);
- return(-3);
- }
-
- }
-
- /*************************************************************************/
- /* cacheupdate
- * We just received an ARP, or reply to ARP and need to add the information
- * to the cache.
- *
- * Reset arptime so that another machine may be ARPed. This timer keeps
- * ARPs from going out more than one a second unless we receive a reply.
- */
- static int32 arptime=0L;
-
- int cacheupdate
- (
- uint8 *ipn,
- uint8 *hrdn
- )
- {
- int i,found;
- int32 timer;
-
- found = -1;
- /*
- * linear search to see if we already have this entry
- */
- for (i=0; found < 0 && i < CACHELEN; i++)
- if (comparen(ipn,&arpc[i].ip,4))
- found = i;
-
- /*
- * if that IP number is not already here, take the oldest entry.
- * If it is already here, update the info and reset the timer.
- * These were pre-initialized to 0, so if any are blank, they will be
- * taken first because they are faked to be oldest.
- */
- if (found < 0) {
- timer = arpc[0].tm;
- found = 0;
-
- for (i=1; i < CACHELEN; i++)
- if (arpc[i].tm < timer && !arpc[i].gate) {/* exclude gateways */
- found = i;
- timer = arpc[i].tm;
- }
- }
- /*
- * do the update to the cache
- */
-
- movebytes(&arpc[found].hrd,hrdn,DADDLEN);
- movebytes(&arpc[found].ip,ipn,4);
- arpc[found].tm = time(NULL);
-
- arptime = 0L; /* reset, allow more arps */
- return(found);
-
- }
-
- /************************************************************************/
- /* reqarp
- * put out an ARP request packet, doesn't wait for response
- */
- int reqarp
- (
- uint8 *tipnum
- )
- {
-
- #ifdef MAC
- if (!EtherNet) { /* BYU 2.4.12 - was KIP */
- if (0 < KIParp(tipnum, (AddrBlock *) &arp.tha))
- cacheupdate(tipnum, &arp.tha);
- return(0);
- }
- #endif MAC
-
- movebytes(&arp.tha,broadaddr,DADDLEN);
- movebytes(&arp.tpa,tipnum,4); /* put in IP address we want */
- arp.op = intswap(ARPREQ); /* request packet */
-
- movebytes(arp.d.dest,broadaddr,DADDLEN); /* send to everyone */
-
- if (dlayersend(&arp,sizeof(arp),0)) /* BYU 2.4.15 */
- return(1); /* error return */
-
- return(0);
- }
-
- /************************************************************************/
- /* interpret ARP packets
- * Look at incoming ARP packet and make required assessment of usefulness,
- * check to see if we requested this packet, clear all appropriate flags.
- */
- int arpinterpret
- (
- ARPKT *p
- )
- {
-
- /*
- * check packet's desired IP address translation to see if it wants
- * me to answer.
- */
- if (p->op == intswap(ARPREQ) && (comparen(&p->tpa,nnipnum,4))) {
-
- cacheupdate(&p->spa,&p->sha); /* keep her address for me */
-
- replyarp(&p->sha,&p->spa); /* proper reply */
- return(0);
- }
- /*
- * Check for a RARP reply. If present, call netsetip()
- */
- else if (p->op == intswap(RARPR) && (comparen(&p->tha,nnmyaddr,DADDLEN))) {
- movebytes(nnipnum,&p->tpa,4);
- return(0);
- }
-
- /*
- * Check for a reply that I probably asked for.
- */
- if (comparen(&p->tpa,nnipnum,4)) {
- if (p->op == intswap(ARPREP) &&
- p->hrd == intswap(HTYPE) && /* consistency checking */
- p->hln == DADDLEN &&
- p->pln == 4 ) {
- cacheupdate(&p->spa,&p->sha);
- return(0);
- }
- }
-
- return(1);
-
- }
-
- /*************************************************************************/
- /* rarp
- * Send a rarp request to look up my IP number
- */
- rarp()
- {
- /*
- * our other fields should already be loaded
- */
- movebytes(&arp.tha,nnmyaddr,DADDLEN); /* address to look up (me) */
- movebytes(&arp.sha,nnmyaddr,DADDLEN); /* address to look up (me) */
- arp.op = intswap(RARPQ); /* request packet */
-
- movebytes(arp.d.dest,broadaddr,DADDLEN); /* send to everyone */
- arp.d.type = ERARP;
-
- if (dlayersend(&arp,sizeof(arp),0)) /* BYU 2.4.15 */
- return(1); /* error return */
-
- arp.d.type = EARP; /* set back for ARP to use */
- return(0);
-
- }
-
- /*************************************************************************/
- /* cachelook
- * look up information in the cache
- * returns the cache entry number for the IP number given.
- * Returns -1 on no valid entry, also if the entry present is too old.
- *
- * doarp is a flag for non-gateway requests which determines whether an
- * arp will be sent or not.
- */
-
- int cachelook
- (
- uint8 *ipn,
- int gate,
- int doarp
- )
- {
- int i,haveg;
- /*
- * First option, we are not looking for a gateway, but a host on our
- * local network.
- */
- if (!gate) {
- for (i=0; i<CACHELEN; i++)
- if (comparen(ipn,&arpc[i].ip,4) &&
- arpc[i].tm + CACHETO > time(NULL))
- return(i);
- /*
- * no valid entry, send an ARP
- */
- if (time(NULL) >= arptime && doarp) { /* check time limit */
- reqarp(ipn); /* put out a broadcast request */
- arptime = time(NULL)+ARPTO;
- }
- return(-1);
- }
- else {
- /*
- * Second option, we need a gateway.
- * if there is a gateway with a current ARP, use it.
- * if not, arp all of the gateways and return an error. Next call will
- * probably catch the result of the ARP.
- */
- haveg = 0;
- for (i=CACHELEN-1; i >= 0; i--)
- if (arpc[i].gate && arpc[i].tm + CACHETO > time(NULL))
- return(i);
-
- if (time(NULL) >= arptime) {
- for (i=CACHELEN-1; i >= 0; i--)
- if (arpc[i].gate) {
- haveg = 1;
- reqarp(&arpc[i].ip); /* put out a broadcast request */
- }
-
- if (!haveg) /* blind luck, try ARPing even for */
- reqarp(ipn); /* a node not on our net. (proxy ARP)*/
-
- arptime = time(NULL)+ARPTO;
- }
-
- return(-1);
- }
-
- }
-
- /***************************************************************************/
- /* netdlayer
- * get data layer address for insertion into outgoing packets.
- * searches based on ip number. If it finds the address, ok, else . . .
- *
- * Checks to see if the address is on the same network. If it is,
- * then ARPs the machine to get address. Forces pause between sending
- * arps to guarantee not saturating network.
- *
- * If not on the same network, it needs the ether address of a
- * gateway. Searches the list of machines for a gateway flag.
- * Returns the first gateway found with an Ethernet address.
- *
- * Returns NULL if not here, or pointer to ether address
- * If we don't have it, this also sends an ARP request so that the
- * next time we are called, the ARP reply may be here by then.
- *
- */
- uint8
- *netdlayer(tipnum)
- uint8 *tipnum;
- {
- int32 t;
- uint8 *pc;
-
- t = time(NULL) + nndto*TICKSPERSEC; /* some seconds time out */
- pc = NULL;
- do {
- if (t <= time(NULL)) /* timed out */
- return(NULL);
- pc = getdlayer(tipnum);
- netsleep(0); /* can't have deadlock */
- } while (pc == NULL);
-
- return(pc);
- }
-
- /***************************************************************************/
- /* netgetrarp
- * Look for a RARP response to arrive
- * wait for nndto seconds before returning failure.
- * If response arrives, return success.
- */
- int netgetrarp
- (
- void
- )
- {
- int32 t,tr;
-
- t = time(NULL) + nndto*TICKSPERSEC*3; /* some seconds time out */
- tr = 0L; /* one second retry */
-
- do {
- if (tr <= time(NULL)) { /* need retry? */
- rarp();
- tr = time(NULL) + TICKSPERSEC;
- }
-
- if (t <= time(NULL)) { /* timed out */
- netposterr(103);
- return(-1);
- }
-
- netsleep(0); /* can't have deadlock */
- } while (comparen(nnipnum,"RARP",4)); /* until RARP is served */
-
- return(0);
- }
-
- /***************************************************************************/
- /* getdlayer
- * check for the hardware address one time
- */
- uint8
- *getdlayer(tipnum)
- uint8 *tipnum;
- {
- int needgate,i;
-
- needgate = 0;
-
- /*
- * Check to see if we need to go through a gateway.
- * If the machine is on our network, then assume that we can send an ARP
- * to that machine, otherwise, send the ARP to the gateway.
- *
- * Uses internet standard subnet mask method, RFC950
- * if subnets are not in use, netmask has been pre-set to the appropriate
- * network addressing mask.
- */
- for (i=3; i >= 0; i--)
- if ((nnmask[i] & tipnum[i]) != (nnmask[i] & nnipnum[i]))
- needgate = 1;
-
- if (needgate && (0 <= (i = cachelook(tipnum,1,1))))
- return(&arpc[i].hrd);
-
- if (!needgate && (0 <= (i = cachelook(tipnum,0,1))))
- return(&arpc[i].hrd);
-
- return(NULL);
- }
-
- /***************************************************************************/
- /* netsetgate
- * Establish an IP number to use as a gateway.
- * They are added in the order that they arrive and there is a limit on
- * the number of gateways equal to CACHELEN/2.
- * ARPs them as they are added so that the Cache will get pre-filled
- * with gateways.
- *
- * returns 0 if ok, -1 on error (full)
- */
- int netsetgate
- (
- uint8 *ipn
- )
- {
- int i;
-
- for (i=CACHELEN-1 ; i >= CACHELEN/2 ; i--)
- if (!arpc[i].gate) {
- arpc[i].gate = 1;
- movebytes(&arpc[i].ip,ipn,4);
- reqarp(ipn);
- return(0);
- }
-
- return(-1);
- }
-